package com.fingard.dsp.bank.directbank.zbf01;

import com.alibaba.fastjson.JSON;
import com.fingard.FGBiz;
import com.fingard.constant.Format;
import com.fingard.dsp.bank.directConfig.ActSetItem;
import com.fingard.dsp.bank.directbank.UnifinedOrderBase;
import com.fingard.dsp.bank.reqrespobj.otherelse.ReqOtherElse;
import com.fingard.dsp.bank.reqrespobj.otherelse.RetAtsOtherElse;
import com.fingard.net.WebRequest;
import com.fingard.text.StringHelper;
import com.fingard.util.SortHelper;
import com.fingard.util.TransIDHelper;
import com.fingard.xml.XmlTextWriter;
import com.zhongbaofu.util.Util;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.*;

public class ZBF01Base extends UnifinedOrderBase {
    protected String getCharset() {
        return getBankConfig().getCharset("utf-8");
    }

    protected String getCharset(String p_def, String p_for) {
        return getBankConfig().getCharset(p_def, p_for);
    }

    private static TransIDHelper idHelper = new TransIDHelper(1, 999);
    protected String getQryTransID() {
        Date tmpDateNow = new Date();
        return Format.DateTime12Year2Format.format(tmpDateNow) + idHelper.getNextIDStr();
    }

    public Map<String, String> removeHead(Map<String, String> tmpMapParams) {
        tmpMapParams.remove("BankCode");
        tmpMapParams.remove("TransType");
        tmpMapParams.remove("CommandCode");
        tmpMapParams.remove("Entity");
        return tmpMapParams;
    }

    protected String getSignStr(Map<String, String> mapParams) {
        Map<String, String> signMap = new HashMap<String, String>();

        for (Map.Entry<String, String> entry : mapParams.entrySet()) {
            String name = entry.getKey();
            String value = entry.getValue();

            if (StringHelper.hasAnyChar(value)) {
                signMap.put(name, value);
            }
        }

        // Map排序
        signMap = SortHelper.sortMapByName(signMap);

        // Map转HTTP字符串
        String signStr = "";
        for (String key : signMap.keySet()) {
            signStr += "&" + key + "=" + signMap.get(key);
        }
        signStr = signStr.substring(1);

        return signStr;
    }

    void writeCommonHeaderVer1(XmlTextWriter xmlWriter, String transSeq) {
        xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
        xmlWriter.writeStartElement("MESSAGE");
        xmlWriter.writeStartElement("MHEAD");
        //接口版本号
        xmlWriter.writeElementString("VERSION", "1.1");
        //流水号C(36)
        xmlWriter.writeElementString("REQSN", transSeq);
        //请求时间yyyyMMddHHmmss
        String transDate = Format.DateTime14Format.format(new Date());
        xmlWriter.writeElementString("PTIME", transDate);
        xmlWriter.writeEndElement();
        xmlWriter.writeStartElement("MBODY");
    }

    void writeCommonQryXml(XmlTextWriter xmlWriter, String mchId, String transSeq, String busType, String askNumber) {
//        xmlWriter.autoFormat = false;
        xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        xmlWriter.writeStartElement("MESSAGE");
        xmlWriter.writeStartElement("MHEAD");
        //接口版本号
        xmlWriter.writeElementString("VERSION", "1.0");
        //业务代码
        xmlWriter.writeElementString("PROCCODE", busType);
        //流水号C(36)
        xmlWriter.writeElementString("REQSN", getQryTransID());
        //请求时间yyyyMMddHHmmss
        String transDate = Format.DateTime14Format.format(new Date());
        xmlWriter.writeElementString("PTIME", transDate);
        xmlWriter.writeEndElement();
        xmlWriter.writeStartElement("MBODY");

        /*支付号*/
        xmlWriter.writeElementString("POLICYID", askNumber);
        /*商户号*/
        xmlWriter.writeElementString("MERCHANTID", mchId);
        /*支付成功中保付返回流水*/
//        xmlWriter.writeElementString("SERIALNUMBER", askNumber);
        xmlWriter.writeEndDocument();
    }
    void writeCommonQryXml1(XmlTextWriter xmlWriter) {
//        xmlWriter.autoFormat = false;
        xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        xmlWriter.writeStartElement("MESSAGE");
        xmlWriter.writeStartElement("MHEAD");
        //接口版本号
        xmlWriter.writeElementString("VERSION", "2.0");
        //流水号C(36)
        xmlWriter.writeElementString("REQSN", getQryTransID());
        //请求时间yyyyMMddHHmmss
        String transDate = Format.DateTime14Format.format(new Date());
        xmlWriter.writeElementString("PTIME", transDate);
        xmlWriter.writeEndElement();
        xmlWriter.writeStartElement("MBODY");
    }

    void writeCommonHeaderVer3(XmlTextWriter xmlWriter, String transSeq, String mchId) {
        xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        xmlWriter.writeStartElement("MHEAD");
        //接口版本号
        xmlWriter.writeElementString("VERSION", "1.3");
        //01保险公司   02中介公司
        xmlWriter.writeElementString("CORSTYLE", "01");
        //商户号
        xmlWriter.writeElementString("INSMERNO", mchId);
        String transDate = Format.DateTime14Format.format(new Date());
        //请求日期yyyyMMdd
        xmlWriter.writeElementString("PDATE", transDate.substring(0, 8));
        //请求时间HHmmss
        xmlWriter.writeElementString("PTIME", transDate.substring(8));
        //请求方流水号
        xmlWriter.writeElementString("TRSSN", transSeq);

        xmlWriter.writeEndElement();
        xmlWriter.writeStartElement("MBODY");
    }

    protected String[] sendToBank(String p_reqStr, String url) throws Exception {
        String[] retStr;
        WriteBankUrlLogLn(url);
        url += URLEncoder.encode(p_reqStr, getCharset());
        WriteBankLogStep2(p_reqStr);
        WebRequest tmpWebRequest = new WebRequest(url);
        tmpWebRequest.setConnectTimeout(60000);
        tmpWebRequest.setRequestProperty("connection", "Close");
        byte[] tmpUpBytes = p_reqStr.getBytes(getCharset());
        retStr = tmpWebRequest.upload(tmpUpBytes, getCharset());
        WriteBankLogStep3(retStr[1]);
        if (retStr[0].length() == 0) {
            int tmpIndex = retStr[1].indexOf("<");
            if (tmpIndex > 0) {
                retStr[1] = retStr[1].substring(tmpIndex);
            }
        } else {
            this.WriteBankLogLn(tmpWebRequest.sbLog);
        }
        return retStr;
    }

    public String[] querySend(String url, String content, ActSetItem actItem) throws Exception {
        String[] retStr = new String[]{"",""};
        CloseableHttpClient httpClient = HttpClients.createDefault();
        WriteBankLogLn2("服务地址:" + url);
        WriteBankLogStep2(content);
        HttpPost httpPost = new HttpPost(url + URLEncoder.encode(content));
        httpPost.addHeader("merchantid", actItem.merchantId);
        RequestConfig.Builder customReq = RequestConfig.custom();
        customReq.setConnectTimeout(10000);
        customReq.setSocketTimeout(10000);
        boolean enableProxy = FGBiz.dspCenter.dspSet.enableProxy;
        if (enableProxy) {
            String proxyIP = FGBiz.dspCenter.dspSet.proxyIP;
            int proxyPort = Integer.parseInt(FGBiz.dspCenter.dspSet.proxyPort);
            HttpHost proxy = new HttpHost(proxyIP, proxyPort,"http");
            customReq.setProxy(proxy);
        }
        httpPost.setConfig(customReq.build());
        CloseableHttpResponse response = httpClient.execute(httpPost);
        HttpEntity entity1 = response.getEntity();
        if(entity1 != null){
            retStr[1] = EntityUtils.toString(entity1, "UTF-8");
        }
        if (retStr[0].length() == 0) {
            int tmpIndex = retStr[1].indexOf("<");
            if (tmpIndex > 0) {
                retStr[1] = retStr[1].substring(tmpIndex);
            }
            int tmpIndex1 = retStr[1].lastIndexOf(">");
            if (tmpIndex1 > 0) {
                retStr[1] = retStr[1].substring(0,tmpIndex1+1);
            }
        }
        WriteBankLogStep3(retStr[1]);
        httpClient.close();
        response.close();
        return retStr;
    }


    public RetAtsOtherElse verifySign(ReqOtherElse p_reqElse) {
        RetAtsOtherElse retAts = new RetAtsOtherElse(p_reqElse.reqHeader);
        retAts.retHashMap = new HashMap<String, String>();
        try {
            String ownAct = "";
            if (p_reqElse.reqHashMap.containsKey("OurBankAccount")) {
                ownAct = p_reqElse.reqHashMap.get("OurBankAccount");
            }
            String merchantId = "";
            if (p_reqElse.reqHashMap.containsKey("MchId")) {
                merchantId = p_reqElse.reqHashMap.get("MchId");
            }
            String appId = "";
            if (p_reqElse.reqHashMap.containsKey("AppId")) {
                appId = p_reqElse.reqHashMap.get("AppId");
            }

            String plain = "";
            if (p_reqElse.reqHashMap.containsKey("Plain")) {
                plain = p_reqElse.reqHashMap.get("Plain");
            } else {
                retAts.retHashMap.put("RespCode", "-1");
                retAts.retHashMap.put("RespInfo", "没有原文参数");
                return retAts;
            }
            ActSetItem actItem = this.getBankConfig().getActSetItemByAny(ownAct, merchantId, appId, "unifiedorder");
            if (actItem != null) {
                StringBuilder tmpSb = new StringBuilder();
                if (verifySignByRSA(plain, actItem.saltKey)) {
                    retAts.retHashMap.put("RespCode", "0");
                    retAts.retHashMap.put("RespInfo", "验签通过");
                } else {
                    retAts.retHashMap.put("RespCode", "-1");
                    retAts.retHashMap.put("RespInfo", tmpSb.toString());
                }
            } else {
                retAts.retHashMap.put("RespCode", "-1");
                retAts.retHashMap.put("RespInfo", "未找到账号[" + ownAct + "]商户配置信息");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            retAts.retHashMap.put("RespCode", "-1");
            retAts.retHashMap.put("RespInfo", ex.getMessage());
            WriteBankLogLn(ex);
        }

        return retAts;
    }

    boolean verifySignByRSA(String plain, String saltKey) throws Exception {
        String startTag = "<MAC>";
        String endTag = "</MAC>";
        if (plain.contains(startTag) && plain.contains(endTag)) {
            String tmpPlain = plain.replaceAll("<MAC>.+</MAC>", "");
            String mac = Util.xorAndGenMac(tmpPlain, saltKey);
            String retMac = plain.substring(plain.indexOf(startTag) + startTag.length(), plain.indexOf(endTag));
            if (mac.equals(retMac)) {
                return true;
            } else {
                return false;
            }
        }
        return false;
    }

    public String hmacsha256(String message, String secret) {
        String encrypt = "";
        try {
            //生成一个指定 Mac 算法 的 Mac 对象
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            //根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
            SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256");
            sha256_HMAC.init(secret_key);
            byte[] bytes = sha256_HMAC.doFinal(message.getBytes());
            encrypt = URLEncoder.encode(new String(Base64.encodeBase64(bytes)));
        } catch (Exception e) {
            WriteBankLogLn("HmacSHA256 MAC 签名生成失败:" + e.getMessage());
        }
        return encrypt;
    }

    public static String buildObjectSortWaitSign(Map<String, Object> mapPars, boolean ExcludeBlankValue) {
        StringBuilder sbPars = new StringBuilder();
        List<String> lsPars = new ArrayList<String>();
        for (Iterator i = mapPars.keySet().iterator(); i.hasNext(); ) {
            String strKey = String.valueOf(i.next());
            if (mapPars.get(strKey) != null && org.apache.commons.lang3.StringUtils.isNotEmpty(mapPars.get(strKey).toString())) {
                lsPars.add(strKey);
            }
        }
        String[] tmpPars = (String[]) lsPars.toArray(new String[lsPars.size()]);
        Arrays.sort(tmpPars);
        for (Integer i = 0; i < tmpPars.length; i++) {
            String strKey = tmpPars[i];
            Object tmpObjValue = mapPars.get(strKey);
            if (null == tmpObjValue) {
                if (ExcludeBlankValue) {
                    tmpObjValue = "";
                } else {
                    continue;
                }
            }
            String strValue = String.valueOf(tmpObjValue);
            if (null == strValue || strValue.length() == 0) {
                if (ExcludeBlankValue) {
                    strValue = "";
                } else {
                    continue;
                }
            }
            if (i == tmpPars.length - 1) {
                sbPars.append(String.format("%s=%s", strKey, strValue));
            } else {
                sbPars.append(String.format("%s=%s&", strKey, strValue));
            }
        }
        return sbPars.toString();
    }

    public String sendToBank(String pFor, Object param, ActSetItem actItem) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            WriteBankLogLn("发送银行的服务地址:" + bankFront.getUrl(pFor));
            URL realUrl = new URL(bankFront.getUrl(pFor));
            URLConnection conn = realUrl.openConnection();
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("mchId", actItem.merchantId);
            conn.setRequestProperty("reqTime", Format.DateTime14Format.format(new Date()));//请求时间
            conn.setRequestProperty("mac", Util.xorAndGenMac(JSON.toJSONString(param), actItem.saltKey));
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常！" + e);
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }
}